Pooka SDK Developer Guide
Programming with Pooka SDK

Basic Programming Requirements

Programming Language

Pooka SDK® is implemented by the native platform SDK through the programming languages specified by each platform. For example, the SDK is implemented by C/C++ for Windows desktop edition, C++/CX for Windows UWP edition, C/Objective-C for iOS/macOS and C++/Java for Android edition.

From the application developer's point of view, the major programming language when using Pooka SDK® is standard C/C++. The following are the basic things about programing with Pooka SDK® that developers need to remember:

  • C/C++ is the programming language used to access Pooka SDK® API. Precisely, C++ 98 is the C++ standard adopted by Pooka SDK®. Although C++ 98 is an aged standard, it provides the maximum compatibility across major C/C++ compilers and offers a less steep learning curve for application developers.
    More modern C++ standard like C++ 11 / 14/ 17 will be adopted in the future version of Pooka SDK®, which can help generate more compact code when programming event-driven and asynchronous applications.
  • There is no language binding in the current edition Pooka SDK® that allows using other programming languages to access Pooka SDK® API.
  • Pooka SDK® is not a closed SDK and developers have full access to the native platform through its platform API. Mixing with other supported programming language in the application source code is absolutely possible, though doing this the application lose the cross-platform capability and the maintenance cost is increased.
    • Access Pooka SDK® API: using C/C++ 98
    • Access native platform API: using any programming language supported by the platform. For eample, developers can:
      • mixing C++ with Objective-C and Swift for macOS / iOS application development
      • mixing C++ with Java and Kotlin for Android application development.
      • mixing C++ with C# for Universal Windows Platform (UWP) application development.

Insecure C/C++ Coding Style Used in the API

Due to historical reason, there are numbers of places in Pooka SDK® API is implemented in insecure coding style. There are various reason of these insecure design in API, such as:

  • For better performance
    At the time when Pooka SDK® is initiated, the early age mobile device are very weak (computing power). The API needs to be implemented in favor of run-time performance.
  • For compiler compatibility
    Due to inconsistent language supports across multiple compilers, which force the API is implemented by the language features supported by all compilers (Visual C++, GCC, CLANG, etc.)

Class variables exposed as public class member

Unlike C#, Kotlin or certain other programming languages, standard C++ language does not support class property and requires programmers to define a pair of accessors so called "setter" and "getter" function instead.

Throughout the Pooka SDK® API, developers will find that only small numbers of setter and getter functions are provided, while many of class variables are exposed directly to developers as public class members. Although exposing class variables as public class members is considered bad practice and can generate unsafe code, Pooka SDK® does this due to historical reason. At the time when Pooka SDK® was started as a cross-platform game engine, mobile devices have extremely weak computing power and memory capacity. Minimizing the memory footprint and reduce processor overhead is one of most important thing that mobile application developers need to take care. Because of this, exposing not-so-complicated class variables instead of providing setter/getter is a practical solution, as soon as it will not easily raise up coding hazard after adequate API reference document is provided. The following picture shows class variables layoutType in class LWComponent and dimension in Object3D are exposed to developers as public class memebrs and there is an extra note reminds developers they should be treated as read-only class members.

In the next major version Pooka SDK®, setters and getters will be applied to replace those unsafe public class member.

Enumeration type is not used in functions signature

Throughout the Pooka SDK® API, developers will find that some functions' parameter or class variables that should be defined by a C enumeration type are actually defined by int type instead, which make these functions and class variables not safe if a value not defined by the enumeration is used to call the function or assign the value of the class variable.
For example, the following API class variables and functions:

  • Content class variable: int bkgBitmapFillMode;
    bkgBitmapFillMode should be defined as enumeration type Content::BACKGROUND_BITMAP_FILLING_MODE
  • Sprite class variable: int guiType;
    guiType should be defined as enumeration type Sprite::GUI_SPRITE_TYPE
  • OGApplication constructor: OGApplication(wchar_t * appName, int graphicsEngineType)
    Parameter graphicsEngineType should be defined as enumeration type Application::GRAPHICS_TYPE
  • GraphicsEngine function: void drawFormattedText(int x, int y, int width, int height, wchar_t * text, unsigned int textColor, int textSize, int alignment, int transparency = 0, bool textBold = false, bool textItalic = false, bool textUnderline = false, bool useMonoFont = false)
    Parameter alignment should be defined as enumeration type GraphicsEngine::TEXT_ALIGNMENT

In the current version Pooka SDK®, developers needs to make sure to use value defined by the corresponding enumeration when assign value or pass in function argument.
In the next major version Pooka SDK®, all those unsafe int type will be replaced by enumeration type.

Traditional C/C++ Memory Management

Pooka SDK® is implemented in traditional C++ coding manner, it does not adopt garbage collection mechanism to recycle allocated memory, nor does it use reference counter or smart pointer to helps semi-automatic object destruction. The following code sample shows allocating and deallocating an array of string buffers by traditional C++ code:

  • Allocate an array of string buffers, with each string can contain 10 characters
    static const int ELEMENT_NUM = 50;
    wchar_t ** nameList = new wchar_t *[ELEMENT_NUM]; //Allocate the array that host string buffers
    for(int i=0; i<ELEMENT_NUM; i++)
    nameList[i] = new wchar_t[10]; //Allocate one string buffers with capacity of 10 characters
  • Deallocate the array of string buffers dynamically created by the code above
    for(int i=0; i<sizeof(nameList)/sizeof(wchar_t *); i++)
    delete [] nameList[i]; //Delete one string buffer
    delete [] nameList; //Delete the array

Throughout the Pooka SDK® API reference, some API functions have to remind developers (in the API reference, highlighted by Caution token) that the returned result (string buffer, memory block, C++ instance, etc.) is dynamically allocated / created on the heap, it is the caller's responsibility to release the returned buffer or destroy the returned instance.

The following document snippet shows a function TypeUtil::valueof(int i) that reminds developers that the returned C string buffer should be released by the caller.

static wchar_t* valueOf ( int  i)
static

Convert a integer into a wide-char C string and return it by pointer.

Caution The returned C string is dynamically created, caller needs to destroy it afterward. <----- Reminder for caller

Parameters
iA integer
Returns
A wide-char C string

Following is a code snippet shows the correct way to use this function:

...
int gameScore = retrieveGameScore(); //Get the final game score
wchar_t * strValue = TypeUtil::valueOf(gameScore); //Create a string contains the final game score
sptGameScore->setText(strValue); //Set the value to the Sprite that displays the game score
delete [] strValue; //Destroy the returned string buffer
...

 Tip  Developers can adopt any garbage collection mechanism or smart pointer in their application source code to help reduce chore in C/C++ memory management. A cross-platform solution is highly recommended for easy maintenance.

Character Set and String Related Programming

Pooka SDK® adopts Unicode character set and UTF-16 for character encoding.

  • All character, string buffer are in wide characters. A single character takes 2 (Windows) to 4 (Unix based) bytes in storage, depends on the platform.
    Application::printf(L"This application (%s) is the first application I developed.\n", appName);
    Sprite * sptTime = this->getScene(L"SceneGUI")->getSprite(L"sptTime");
    sptTime->setText(currentTime->toString());
  • Always use wide character type whcar_t for character and string buffer type
    wchar_t * myString = L"Hello, world!";
    wchar_t ch5 = myString[5]; //Access the 5th character
    for(wchar_t * p = myString; p<myString + wcslen(myString); p++)//Loop over every character in the string buffer
    {
    wchar_t * ch = *p;
    Application::printf(L"The character[%d] = %c\n", (int)(p-myString), ch); //Print one character on debug console
    }
  • Using C standard library or third party library for string operation
    Using string related functions provided by C standard library (defined in <string.h>) or third party library is acceptable. However, doing this will make the source code lose the cross-platform compatibility. For example, functions such as wcscpy(), wcscat(), wcslen(), wcsstr() and wcschr() may not have identical function name and parameter signature.
    Pooka SDK® provides two classes String and StrBuf help achieve cross-platform coding for string related operations. Following code compares the different coding style to concatenate several strings and get the length of the concatenated result.
    Using C standard function:
    wchar_t * str1 = L"Pooka SDK";
    wchar_t * str2 = L"is a";
    wchar_t * str2 = L"cross-platform app engine.";
    wchar_t sentence[1024];
    wcscat(wcscat(wcscat(wcscat(wcscpy(sentence, str1), L" "), str2), L" "), str3); //concatenate all strings
    int len = wcslen(sentence); //Get the lenght of the final string
    Using Pooka SDK® String class:
    wchar_t * str1 = L"Pooka SDK";
    wchar_t * str2 = L"is a";
    wchar_t * str2 = L"cross-platform app engine.";
    String sentence = String(str1) + L" " + str2 + L" " + str3; //concatenate all strings
    int len = sentence.length(); //Get the lenght of the final string

Coding for Cross-platform

When coding for a cross-platform application, take good care of the coding manner, which can affect the application performance and maintenance efficiency. As fas as the easy maintenance is concerned, developers should try to code the application in cross-platform coding manner. Although Pooka SDK® promises that API is fully cross-platform, there are other application source code written by developers may be platform dependent. Try to minimize the amount of platform dependent source code helps reduce maintenance cost. What developers can do are, for example:

  • Avoid using platform dependent API. If absolutely needed, encapsulated by an utility function or a class so that they are maximumly isolated from the major part of application source code.
  • Generate an abstraction layer for large module that has to be implemented by platform dependent API.
  • If a third part library is needed. Check if the library is fully cross-platform. If not, make a cross-platform wrapper for the library.
  • Avoid using specific compiler features, such as compiler preprocessor. For example, compiler directive #pragma is commonly used in source code for build-time compilation tune-up. Unfortunately, #pragma is platform dependent. What developers can do is create platform neutral macros around these #pragma. In this case the equivalent pragma operator _Pragma("argument") should be used (introduced in C99 standard). The following code shows an example of define a cross-platform pragma wrapper:
    #if defined (_MSC_VER) //Microsoft Visual C/C++
    #define MY_CROSSPLATFORM_PRAGMA _Pragma("argument")
    #elif defined (__GNUC__) //GCC
    #define MY_CROSSPLATFORM_PRAGMA _Pragma("alt argument")
    #else //All other compiler
    #define MY_CROSSPLATFORM_PRAGMA _Pragma("alt argument")
    #endif

Coding for Device Fragmentation

Sometimes the platform's fragmentation make it inevitable to have fragmented code in a cross-platform application project. For example, when implemented hardware related modules, such as camera, mobile sensors, NFC and bluetooth, developers may need to write code specific to each platform.

Pooka SDK® provides technical assistance at the build-time and run-time to help application deal with platform fragmentation and maximumly reduce the maintenance cost.

Fragmentation Assistance at the Build-time

Numbers of preprocessors are provided to detect target platform at the build-time. Using build-time detection can helps generate more compact and efficient application binary.

Detect Target Platform at build-time

The following preprocessor helps detect the platform at the build-time (compile-time)

Preprocessor Meaning
_POOKA_TARGET_WINDESKTOP Build for Windows Desktop
_POOKA_TARGET_WINUWP Build for Windows UWP platform
_POOKA_TARGET_MACOS Build for macOS
_POOKA_TARGET_IOS Build for iOS
_POOKA_TARGET_ANDROID Build for Android
_POOKA_TARGET_DESKTOP_OS Build for Desktop platform (Windows and macOS)

Detect Target Processor architecture

Preprocessor Meaning
_POOKA_TARGET_ARCH_X86 Build for Intel x86 architecture
_POOKA_TARGET_ARCH_ARM Build for Intel ARM architecture
_POOKA_TARGET_ARCH_64 Build for 64-bit architecture
_POOKA_TARGET_ARCH_32 Build for 32-bit architecture

Detect Build Configuration

Preprocessor Meaning
_POOKA_TARGET_DEBUG Build with debug configuration
_POOKA_TARGET_RELEASE Build with release configuration

Example 1:

#if defined (_POOKA_TARGET_ANDROID) && defined (_POOKA_TARGET_ARCH_ARM) && defined (_POOKA_TARGET_ARCH_64)
// Some code dedicated to Android device with ARM64 architecture ...
#elif defined (_POOKA_TARGET_WINUWP) && defined (_POOKA_TARGET_ARCH_X86) && defined (_POOKA_TARGET_ARCH_32)
// Some code dedicated to Windows UWP platform with X64 architecture ...
#else

Example 2:

void MyClass::myFunction()
{
#if defined (_POOKA_TARGET_DEBUG) // Build with Debug config
Application::debugPrintf(L"Function myFunction() is called!"); //Print a debug message
#else
...
}

Fragmentation Assistance at the Run-time

Run-time platform detection happens only after application is running on the target device. Thus it is not efficient as build-time detection and may apply some minor overheads.

Run-time platform detection is done through numbers of classes and their properties, which are scattered but mostly in several classes including RealDevice , VirtualDevice , Application and Content .

Detect Target OS Info

Caution osVersionMajor and osVersionMinor are not fully implemented in current Pooka SDK®, if the info can not be retrieved, they are simply 0.

Example:

...
if(RealDevice::osSubtype == RealDevice::OS_SUBTYPE_WINUWP_DESKTOP || RealDevice::osSubtype == RealDevice::OS_SUBTYPE_WINUWP_MOBILE) //Windows Store App
{
// Some code dedicated to Windows Store App goes here...
}
...

Real Device's Display Properties Detection

Example:

...
if(RealDevice::osSubtype == RealDevice::OS_MACOS_IOS || RealDevice::osSubtype == RealDevice::OS_SUBTYPE_IOS) //iOS Device
{
if(RealDevice::physicalDisplayWidth == 1125 && RealDevice::physicalDisplayHeight == 2436)//1125x2436, iPhone X
{
// Some code dedicated to iPgone X goes here...
}
else //Other iOS device
{
...
}
}
...

Virtual Device's Display Properties Detection

Miscellaneous Target Device Property Detection



Coding for Commercial Application

When programming a commercial application (applications published at online store for profit purpose), there are several things that developers need to pay attention further:

  • Make the application meet publisher's certification criteria
  • Promote developers' own branded content

Application certificate criteria for App Store

To most application developers, the final step of developing an application is to publish their application and sell it at platform's app store. Before an application cab be listed at platform's app store, the application must get certified by app store's certification process.

The technical details of this application certification process is beyond the scope of Pooka SDK®, besides each platform's app store may have specific certificate when assessing application.

Generally, the certification process usually has the following assessment conducted:

  • Security tests
    • checks application's packages for viruses and malware.
    • checks if undocumented, disallowed deprecated classes, functions are used.
    • checks if permission is declared in application's manifest for privileged functions.
    • checks sandbox compliance for mobile platforms
  • Technical compliance tests
    • Application tun-time behaviors
    • Human Interface design
      • Graphics user interface design
      • Icon, launch (splash) image, screen-shot
    • Application package
  • Content compliance

Developers need to spend time on each platform's application publishing guideline to prepare their application for compliance of application certification criteria. The following are some reference link for each platforms:

Publish Android apps
Apple AppStore guidelines
Publish Windows apps

Promote developers' own branded content

At application design time, there are numbers of ways to prompt developers' own branded content. For example, using customized launch image, splash image, icons, banners that can reflect brand and business image. Each platform has a detailed guideline about how to prepare those UI elements.

If an application is built by Pooka SDK® commercial edition, developers are able to set a customized splash image shown for short moment. Please note:

  • This customized splash image shows up after the application is launched.
  • The splash image period occupies the main UI thread and usually can not be used for doing application initialization.
  • If the application is built by Pooka SDK® trail/community edition, then a default "powered by Pooka SDK" splash image is shown for about 2 second and there is no way to remove it or change the splash image.

The customized splash image can be set through function Application::setCustomSplashImage() , refer to the API reference for more details. The following code sample shows setting a customized splash image for an application based on OGApplication class:

void MyApplication::defaultPreCreationProc()
{
OGApplication::defaultPreCreationProc(); //Important! Must call the default implementation defined in class OGApplication first.
Application::setCustomSplashImage(Bitmap::loadFromAsset(String(Application::getAssetsPath()) + L"logo.png"), 3.f);//Set custom splash image
}

Further Reading

Read Pooka SDK® API Reference Overview to get a quick overview about Pooka SDK® API.